/* eslint-disable max-lines-per-function */
import { ref } from "vue";
import { cloneDeep } from "lodash-es";
import { ElMessage as Message } from "element-plus";
import { useResource } from "./useResource";

const lang = {
  selectRowMsg: "至少选择一行记录",
};

export type ListResponseType = {
  code: string | number;
  data: {
    list: unknown[];
    totalCount: number;
    totalPage: number;
    pageNo: number;
    pageSize: number;
    offset: number;
  };
};

export const useTableList = <
  IResponseType extends ListResponseType,
  ICondition,
  IConditionBefore = ICondition
>(
  listApi: (data: ICondition) => Promise<IResponseType>,
  Options: {
    foreignModel?: object | undefined;
    pageNoName?: string | undefined;
    pageSizeName?: string | undefined;
    /** 在请求之前，变化请求参数 */
    beforeGetList?: (condition: IConditionBefore) => ICondition | false;
    /** 获取请求之后都会触发这个 */
    afterGetList?: (res: IResponseType) => void | Promise<void>;
  }
) => {
  type IRowData = IResponseType extends { data: { list: (infer R)[] } }
    ? R
    : unknown;
  /** 当前页码*/
  const pageNo = ref(1);
  /** 列表总数量*/
  const pageTotal = ref(0);
  /** 每页数量*/
  const pageSize = ref(10);

  /** 列表数据*/
  const totalData = ref<IRowData[]>([]);
  /** 被选中的行*/
  const selectedRows = ref<IRowData[]>([]);
  /** 列表搜索参数*/
  const searchModel = ref({});
  /** 列表外键从参数 （不随搜索器变化的参数，基础搜索参数）*/
  const foreignModel = ref(Options?.foreignModel || {});

  /** 页码参数名字*/
  const pageNoName = Options?.pageNoName || "pageNo";
  /** 每页数量参数名字*/
  const pageSizeName = Options?.pageSizeName || "pageSize";
  const {
    refetch: fetchAPI,
    /** 列表加载状态*/
    loading: tableLoading,
  } = useResource(listApi);
  /**
   * 加载列表信息
   * @param data:Object          列表搜索参数
   * @param lazyLoad:Boolean      true则懒加载
   */
  const getList = (data = {}, lazyLoad = false) => {
    if (!listApi) {
      throw new TypeError("请先配置Options.Api.listApi");
    }

    // 分页参数为可变参数名
    const condition = cloneDeep({
      [pageNoName]: pageNo.value,
      [pageSizeName]: pageSize.value,
      ...searchModel.value,
      ...foreignModel.value,
      ...data,
    }) as IConditionBefore;

    const conditionData: ICondition | false =
      Options?.beforeGetList?.(condition) ??
      (condition as unknown as ICondition);
    if (conditionData !== false && typeof conditionData !== "object") {
      throw new TypeError(
        "beforeGetList 方法必须返回 Object:{} 或 Boolean:false"
      );
    }
    // 钩子方法返回false，则不发起列表请求
    if (conditionData === false) {
      return false;
    } else {
      return fetchAPI(conditionData).then((res) => {
        if (lazyLoad === false) {
          return afterGetList(res);
        } else {
          return afterGetListLazy(res);
        }
      });
    }
  };
  /**
   * 设置外键信息并重加载列表
   * @param foreignModel { key:value }
   */
  const updateListForeion = (foreignModel: Record<string, any>) => {
    // 重置分页
    pageNo.value = 1;
    // 设置新的外键参数
    foreignModel.value = foreignModel;
    // 重置搜索参数
    searchModel.value = {};
    // 重新加载列表
    getList({}, false);
  };
  /**
   * 分页大小响应
   * @param newSize:Number 每页数量
   */
  const sizeChange = (newSize: number) => {
    pageNo.value = 1;
    pageSize.value = newSize;
    getList();
  };

  /**
   * 页码变化响应
   * @param newPage:Number 页码
   */
  const pageChange = (newPage: number) => {
    pageNo.value = newPage;
    getList();
  };

  /**
   * 搜索列表
   * @param searchParams:Object  搜索参数{ }
   */
  const searchList = (searchParams = {}) => {
    pageNo.value = 1;
    searchModel.value = searchParams;
    getList();
  };

  /**
   * 表格选中的行
   * @param selectedRow:Array  选中的行数据 [{},{}]
   */
  const handleSelectedRow = (selected: IRowData[] = []) => {
    selectedRows.value = selected;
  };

  /**
   * 用于懒加载，当前分页加一
   */
  const lazyGetList = (data = {}) => {
    pageNo.value += 1;
    getList(data, true);
  };

  /**
   * 获取列表成功回调，常规赋值
   * @param res：JSON   列表接口返回的数据
   */
  const afterGetList = async (res: IResponseType) => {
    if (Options?.afterGetList) {
      await Options.afterGetList(res);
    }
    if (+res.code === 0) {
      console.log("123", res.data.list);
      // 由于 res.data.list 是 unknown[] 类型，需要进行类型断言来解决类型不匹配问题
      totalData.value = res.data.list as IRowData[];
      pageTotal.value = res.data.totalCount;
    }
  };

  /**
   * 懒加载列表成功回调，如果是懒加载，则push进入List
   * @param res：JSON    列表接口返回的数据
   */
  const afterGetListLazy = (res: IResponseType) => {
    if (+res.code === 0) {
      totalData.value.push(...(res.data.list as UnwrapRef<IRowData[]>));
      pageTotal.value = res.data.totalCount;
    }
  };

  /**
   * 用于检查是否至少选择了一行数据  用于批量操作的前置检查
   * @param mag :String               没有选择行时候的提示消息
   * @returns Boolean      返回true则至少选择了一行
   */
  const isCheckedAtLeastOneRow = (msg = "") => {
    if (selectedRows.value.length < 1) {
      Message.info(msg || lang.selectRowMsg);
      return false;
    } else {
      return true;
    }
  };

  return {
    listApi,
    pageNo,
    pageTotal,
    pageSize,
    tableLoading,
    totalData,
    selectedRows,
    searchModel,
    foreignModel,
    pageNoName,
    pageSizeName,
    updateListForeion,
    isCheckedAtLeastOneRow,
    handleSelectedRow,
    sizeChange,
    pageChange,
    searchList,
    lazyGetList,
  };
};
